//自定义人类型
type Person = {
    name: string
    nikeName: string
    age: number

}
type PersonProp = {
    sex?: '男' | '女' | 0 | 1
    isPlayGame : boolean
}
type tongxue = Person & PersonProp

// ------------------------------------------------------------------------------

// Partial<Type>: 翻译为: 部分的,不完全的. 作用: 把类型定义为可选
// Required<Type> 把类型定义为必选

type tongxuePartial = Partial<tongxue>
type tongxueRequired = Required<tongxuePartial>

// 自定义
type CustomPartial<T> = {
    // keyof : 得到泛型的所有key组成的联合类型  ==>  name | nikeName | age | sex | isPlayGame. in: 用于遍历联合类型的每一项
    [P in keyof T]? : T[P] 
}
type CustomRequired<T> = {
    [P in keyof T] -? : T[P] 
}

type tongxuePartial2 = CustomPartial<Person & PersonProp>
type tongxueRequired2 = Required<tongxuePartial2>

// ------------------------------------------------------------------------------
/* 
    Record(记载): 构造一个对象类型，其属性键为keys，属性值为type。此实用程序可用于将一个类型的属性映射到另一个类型。
*/
type tongxueList = Record<'xiaoming' | 'xioanghong', tongxue>
// 自定义
type  CustomRecord<K extends number | string | symbol, T> = {
    [P in K] : T
}
type tongxueList2 = CustomRecord<'xiaoming' | 'xioanghong', tongxue>

// ------------------------------------------------------------------------------

/*  
   Pick: 翻译为 --- 采, 摘.  
         接收两个参数: 1: 约束的类型, 2: 采集的具体属性的联合类型,  return 采集后的类型
         作用: 用于采集约束类型中的指定属性和值, 如果给定属性不存在,编译器报错 
*/

type tongxuePick = Pick<tongxue, 'name' | 'isPlayGame'>
// pick内部实现
// 泛型 的 extends， 与 运算的 extends 需要稍微留心做个区分。 这次看 extends 在这里充当 类似于判断的 "约束" 角色
// K extends keyof T : 用于判断类型 K 是否是 联合类型(keyof T) 的子集
type CustomPick<T, K extends keyof T> =  { 
    [P in K] : T[P] // 遍历 K 获取属性, 在对每一项在求值
}
type tongxuePick2 = CustomPick<tongxue, 'name' | 'isPlayGame'>

// ------------------------------------------------------------------------------

/* 
    Exclude: 翻译为 --- 不包括.  另外的名字 Diff
             接收两个参数: 1: 联合类型, 2: 联合类型,  返回值: 对比后的联合类型
             作用: 参数1内的每一项和参数2比较,如果相同,就从参数1中删除, 将最终结果返回
    Extract: 提取 另外的名字 Filter
    Diff / Filter 功能和着两个一样
*/
type tongxueExclude = Exclude<keyof tongxue, 'name' | 'age' >
type tongxueExtract = Extract<keyof tongxue, 'nikeName' | 'isPlayGame' | 1>
// 自定义Exclude /  Extract
/* 
   T extends U ? never : T 执行步骤
            T 里面的 "name" 是否是 U 的 "name | age" 的子集？ 符合， 返回 never ，既 什么都没有。
            T 里面的 "nikeName" 是否是 U 的 "name | age" 的子集？ 不符合 返回 "nikeName" 本身。
            T 里面的 "age" 是否是 U 的 "name | age" 的子集？ 符合 返回 never, 既 什么都没有。。
            T 里面的 "sex" 是否是 U 的 "name | age" 的子集？ 不符合 返回 "sex" 本身。
            T 里面的 "isPlayGame" 是否是 U 的 "name | age" 的子集？ 不符合 返回 "isPlayGame" 本身。
        运算中的 extends 和 泛型中的 extends的区别: 
            在运算中: 会遍历 左侧的联合联合类型 的每一项 依次求是否是 右侧联合类型 的子集,并执行后面的三目运算逻辑
            在泛型中: 会直接求左侧联合类型是否是右侧联合类型的子集
*/
type CustomExclude<T, U> = T extends U ? never : T

type CustomExtract<T, U> = T extends U ? T : never

type tongxueExclude2 = CustomExclude<keyof tongxue, 'name' | 'age' > 
type tongxueExtract2 = Extract<keyof tongxue, 'nikeName' | 'isPlayGame'>

/* 
   在条件判断类型的定义中，将泛型参数使用[]括起来，即可阻断条件判断类型的分配，此时，传入参数T的类型将被当做一个整体，不再分配。
  [T] extends ['x' | 'y']
*/
type P<T> = [T] extends ['x' | 'y'] ? T : never
type P1 = P<'x' | 'y'>
type P2 = P<'x' | 'y' | 'z'>
type P3 = P<'x'>
type D<T> = T extends 'x' | 'y' ? T : never
type D1 = D<'x' | 'y'>
type D2 = D<'x' | 'y' | 'z'>
type D3 = D<'x'>
// type F<T, D> = T extends [D] ? T : never
// type F1 = F<'x' | 'y', 'x' | 'y'>
// type F2 = P<'x' | 'y' | 'z'>
// type F3 = P<'x'>

// ------------------------------------------------------------------------------

/* 
    Omit: 翻译为 省去
            接收两个参数, 1: 要操作的类型, 2: 需要省去的key的联合类型, 返回值: 省去属性后的新类型
            只会删除第一个参数的类型中包含的第二个参数的联合类型的key
*/
type tongxueOmit = Omit<tongxue, 'age' | 'name'>
/* 
    自定义Omit
        CustomPick<T, CustomExclude<keyof T, K>> 执行步骤
            先执行CustomExclude删除指定的key
            在执行CustomPick 生成新的类型并返回
*/

type CustomOmit<T, K> = CustomPick<T, CustomExclude<keyof T, K>>

type tongxueOmit2 = CustomOmit<tongxue, 'age' | 'name'>

// ------------------------------------------------------------------------------

/* 
     infer 与 typeof 关键字
        infer: 意思是待推导一个泛型，在这里形容更像是一个 "标记"
               我在这里先把 V 给标记了，等下你们给我推出这个 V 的类型然后让我用！
        typeof: 在泛型中的typeof是用来返回一个类型
                whatIsWangyou<typeof wangyouList> 这个泛型中返回的应该是 wangyou[] 这个类型
                wangyouList这个数组的类型就是 wangyou[]

        whatIsWangyou类型中的代码执行
                T extends Array<infer V> ? V : never 用于标记类型 V
                T = Array<wangyou> 
                Array<infer V> === Array<wangyou>
                V === wangyou
                最终返回 V 即 wangyou 这个类型
*/
// 声明一个网友类型
type wangyou = CustomPick<tongxue, 'nikeName'> & CustomPartial<PersonProp>
const wangyouList : wangyou [] = []
type whatIsWangyou<T> = T extends Array<infer V> ? V : never
const newWangyou: whatIsWangyou<typeof wangyouList> = {
    nikeName: '我是网友',
    sex: 0,
    isPlayGame: true
}

// ------------------------------------------------------------------------------
/* 
    NonNullable<Type>: 通过从type中排除null和undefined
*/
type testNonNullable = string | number | null | undefined
type delNull = NonNullable<testNonNullable>
//自定义
type CustomNonNullable<T> = T extends null | undefined ? never : T
// type CustomNonNullable2<T> = T & {}
type delNull2 = CustomNonNullable<testNonNullable>



// ------------------------------------------------------------------------------
/* 
    ReturnType<Type> : 获取函数类型返回的类型
*/

const f1 = (item: tongxue ) => {
    return item
}
type testReturnType =  ReturnType<typeof f1>

// 自定义
type CustomReturnType<T extends (...args : any) => any> = T extends (...args: any) => infer R ? R : any
type testReturnType1 = CustomReturnType<typeof f1>
type testReturnType2 = CustomReturnType<() => number>
type testReturnType3 = CustomReturnType<tongxue> //此处必须传递function类型

// ------------------------------------------------------------------------------
/* 
    InstanceType<Type>: 构造由“类型”中构造函数的实例类型组成的类型。

*/
class testT{
    A: string = ''
    B?: number = 0
    C: boolean = false
}
// 自定义 
/* 
    abstract : 抽象类吗?, 貌似不加也可以, 官方是这么写的
    这个工具不知道是要用在哪
    因为   直接指定testT这个类作为类型  === 使用这个工具返回的类型
*/
type CustomInstanceType<T extends abstract  new (...args: any) => any > =  T extends abstract  new (...args: any) => infer R ? R : any
type testCustomInstanceType = CustomInstanceType<typeof testT>
const InstanceTypeRes: testCustomInstanceType [] = [{
    A: '我是A',
    B: 1,
    C: true
}]
const InstanceTypeRes2: testT [] = [{
    A: '我是A',
    B: 1,
    C: true
}]
// ------------------------------------------------------------------------------
/* 
    ThisParameterType<Type>: 为函数类型提取this形参的类型，如果函数类型没有this形参则为未知。 
    this的类型为 TS 内置接口 Number 应该是用来约束 js Number类的
*/
function toHex(this: Number) {
    return this.toString(16);
  }
   
function numberToString(n: ThisParameterType<typeof toHex>) {
    return toHex.apply(n);
}
// 自定义
type CustomThisParameterType<T> = T extends (this: infer C, ...args: never) => any ? C : unknown
function numberToString2(n: CustomThisParameterType<typeof toHex>) {
    return toHex.apply(n);
}

// ------------------------------------------------------------------------------
/* 
    OmitThisParameter<Type> : 从类型中移除this参数。如果Type没有显式声明此参数，则结果仅为Type。
                              否则，将从type创建一个不带此参数的新函数类型。泛型被擦除，只有最后一个重载签名被传播到新的函数类型中。
    此工具估计很少会用到
    
*/
   
const fiveToHex: OmitThisParameter<typeof toHex> = toHex.bind(5);

console.log(fiveToHex());
